#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <dirent.h>
#include <resolv.h>
#include <signal.h>
#include <getopt.h>
#include <string>

#include "Socket.h"
#include "File.h"
#include "HttpServerCfg.h"

using namespace std;

#define MAXBUF        1024
#define MAXPATH        128

#define HTTPSERVER_CFG_FILE_PATH "/Users/champon/http_server/http_server/http_server/test_httpd.conf"

void wrtinfomsg(string msg)
{
	syslog(LOG_INFO, "%s", msg.c_str());
}

char file_type(mode_t st_mode)
{
	if ((st_mode & S_IFMT) == S_IFSOCK)
		return 's';
	else if ((st_mode & S_IFMT) == S_IFLNK)
		return 'l';
	else if ((st_mode & S_IFMT) == S_IFREG)
		return '-';
	else if ((st_mode & S_IFMT) == S_IFBLK)
		return 'b';
	else if ((st_mode & S_IFMT) == S_IFCHR)
		return 'c';
	else if ((st_mode & S_IFMT) == S_IFIFO)
		return 'p';
	else
		return 'd';
}

//search the up-path of dirpath
char *dir_up(char *dirpath)
{
    static char Path[MAXPATH];
    size_t len;

    strcpy(Path, dirpath);
    len = strlen(Path);
    if (len > 1 && Path[len - 1] == '/')
        len--;
    while (Path[len - 1] != '/' && len > 1)
        len--;
    Path[len] = 0;
    return Path;
}


 //send the path data to client ;if path is a file ,send the data, if path is a dir, list
void GiveResponse(FILE * client_sock, char *Path)
{
    struct dirent *dirent;
    struct stat info;
    char Filename[MAXPATH];
    DIR *dir;
    int fd;
    ssize_t ret;
    unsigned long len;
    char *p, *realPath, *realFilename;

	struct passwd *p_passwd;
	struct group *p_group;
	char *p_time;

    struct HttpServerCfgDef cfg = HttpServerCfg::getHttpServerCfgDef();
	//get th dir or file
    len = cfg.homeDir.size() + strlen(Path) + 1;
    realPath = (char*)malloc(len + 1);
    bzero(realPath, len + 1);
    sprintf(realPath, "%s/%s", cfg.homeDir.c_str(), Path);
    printf("realpath is .%s.\n", realPath);

	//get port
    char nport[20];
    memset(nport, '\0', sizeof(nport));
    sprintf(nport, ":%u", cfg.port);

	//get file state to get the information :dir or file
    if (stat(realPath, &info)) {
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer:Test http server\r\nConnection: close\r\n\r\n<html><head><title>%d - %s</title></head>"
                "<body><font size=+4>Linux HTTP server</font><br><hr width=\"100%%\"><br><center>"
                "<table border cols=3 width=\"100%%\">",
                errno,
                strerror(errno));
        fprintf(client_sock,
                "</table><font color=\"CC0000\" size=+2> connect to administrator, error code is: \n%s %s</font></body></html>",
                Path, strerror(errno));
        goto out;
    }

	//if file ,send file
    if (S_ISREG(info.st_mode))
	{
        fd = open(realPath, O_RDONLY);
        len = lseek(fd, 0, SEEK_END);
        p = (char *) malloc(len + 1);
        bzero(p, len + 1);
        lseek(fd, 0, SEEK_SET);
        ret = read(fd, p, len);
        close(fd);
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer: Test http server\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%lu\r\n\r\n", len);

		fwrite(p, len, 1, client_sock);
        free(p);
    }
	else if (S_ISDIR(info.st_mode))
	{

	//if dir,list the dir
        dir = opendir(realPath);
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer:Test http server\r\nConnection:close\r\n\r\n<html><head><title>%s</title></head>"
                "<body><font size=+4>Linux HTTP server file</font><br><hr width=\"100%%\"><br><center>"
                "<table border cols=3 width=\"100%%\">", Path);
        fprintf(client_sock,
                "<caption><font size=+3> Directory %s</font></caption>\n",
                Path);
        fprintf(client_sock,
                "<tr><td>name</td><td>type</td><td>owner</td><td>group</td><td>size</td><td>modify time</td></tr>\n");
        if (dir == NULL) {
            fprintf(client_sock, "</table><font color=\"CC0000\" size=+2>%s</font></body></html>",
                    strerror(errno));
            return;
        }
        while ((dirent = readdir(dir)) != NULL)
		{
            if (strcmp(Path, "/") == 0)
                sprintf(Filename, "/%s", dirent->d_name);
            else
                sprintf(Filename, "%s/%s", Path, dirent->d_name);
            if(dirent->d_name[0]=='.')
				continue;
		    fprintf(client_sock, "<tr>");
            len = strlen(cfg.homeDir.c_str()) + strlen(Filename) + 1;
            realFilename = (char*)malloc(len + 1);
            bzero(realFilename, len + 1);
            sprintf(realFilename, "%s/%s", cfg.homeDir.c_str(), Filename);
            printf("a:http://%s%s%s\n", cfg.ip.c_str(), cfg.port == 80 ? "" : nport, dir_up(Path));
            printf("b:http://%s%s%s\n", cfg.ip.c_str(), cfg.port == 80 ? "" : nport, Filename);

            if (stat(realFilename, &info) == 0)
			{
                if (strcmp(dirent->d_name, "..") == 0)
                    fprintf(client_sock, "<td><a href=\"http://%s%s%s\">(parent)</a></td>",
                            cfg.ip.c_str(), cfg.port == 80 ? "" : nport, dir_up(Path));
                else
                    fprintf(client_sock, "<td><a href=\"http://%s%s%s\">%s</a></td>",
                            cfg.ip.c_str(), cfg.port == 80 ? "" : nport, Filename, dirent->d_name);

	          	p_time = ctime(&info.st_mtime);
	           	p_passwd = getpwuid(info.st_uid);
	           	p_group = getgrgid(info.st_gid);

                long long  nFileSize = info.st_size;
                int nMeasurement =1;
                for (long long limit = 1; info.st_size >= (limit <<=  10); ++ nMeasurement)
                    nFileSize = (info.st_size / limit);
                
                char szFileSize[20];
                memset(szFileSize, '\0', sizeof(szFileSize));
                string szMeasurement;
                switch (nMeasurement) {
                    case 1:
                        szMeasurement = "bytes";
                        break;
                    case 2:
                        szMeasurement = "k";
                        break;
                    case 3:
                        szMeasurement = "M";
                        break;
                    case 4:
                        szMeasurement = "G";
                        break;
                    default:
                        szMeasurement = "";
                        break;
                }
                sprintf(szFileSize, "%lld %s", nFileSize, szMeasurement.c_str());
                
			  	fprintf(client_sock, "<td>%c</td>", file_type(info.st_mode));
			   	fprintf(client_sock, "<td>%s</td>", p_passwd->pw_name);
		      	fprintf(client_sock, "<td>%s</td>", p_group->gr_name);
			  	fprintf(client_sock, "<td>%s</td>", szFileSize);
				fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime));
            }
            fprintf(client_sock, "</tr>\n");
            free(realFilename);
        }
        fprintf(client_sock, "</table></center></body></html>");
    } else {
      //if others,forbid access
        fprintf(client_sock,
                "HTTP/1.1 200 OK\r\nServer:Test http server\r\nConnection: close\r\n\r\n<html><head><title>permission denied</title></head>"
                "<body><font size=+4>Linux HTTP server</font><br><hr width=\"100%%\"><br><center>"
                "<table border cols=3 width=\"100%%\">");
        fprintf(client_sock,
                "</table><font color=\"CC0000\" size=+2> you access resource '%s' forbid to access,communicate with the admintor </font></body></html>",
                Path);
    }
  out:
    free(realPath);
}


void init_daemon(const char *pname, int facility)
{
	int pid;
	int i;
	signal(SIGTTOU,SIG_IGN);
	signal(SIGTTIN,SIG_IGN);
	signal(SIGTSTP,SIG_IGN);
	signal(SIGHUP ,SIG_IGN);
    
    pid=fork();
	if((pid))
		exit(EXIT_SUCCESS);
	else if(pid< 0)
	{
		perror("fork");
		exit(EXIT_FAILURE);
	}
	setsid();
    pid=fork();
	if(pid)
		exit(EXIT_SUCCESS);
	else if(pid < 0)
	{
		perror("fork");
		exit(EXIT_FAILURE);
	}
	for(i=0; i< NOFILE; ++i)
		close(i);
	chdir("/tmp");
	umask(0);
	signal(SIGCHLD,SIG_IGN);
	openlog(pname, LOG_PID, facility);
	return;
}


